<?php
class mysqldatasource
{ 
    private $dsn;
    private $username;
    private $password;
    private $connection;
    private $charset;

    public static $connections = array();
    public static $max_connection_count = 3;

    public function __construct($dbhost, $dbname, $username, $password, $charset='utf8') {
        $this->dsn = "mysql:host=$dbhost;dbname=$dbname;";
        $this->username = $username;
        $this->password = $password;
        $this->charset = $charset;
    }
    public function connect4Write() {
        if ($this->isConnect() == false) {
            self::checkMaxConnection();

            $connection = new PDO($this->dsn, $this->username, $this->password,
                //array(PDO::MYSQL_ATTR_INIT_COMMAND => "set names {$this->charset}"));
                array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET character_set_connection={$this->charset}, character_set_results={$this->charset}, character_set_client=binary"));
            $connection->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
            $connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $connection->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
            $connection->setAttribute(PDO::ATTR_AUTOCOMMIT, true);

            $this->setConnection($connection);
        }
        return $this->getConnection();
    }
    public function mustUseMaster($must = true) {
    }
    public function connect4Read() {
        return $this->connect4Write();
    }
    public function getConnectionStatus(){
        return $this->getConnection()->getAttribute(PDO::ATTR_CONNECTION_STATUS);
    }
    public function getConnectionStatus4Read()
    {/*{{{*/
        return $this->getConnectionStatus();
    }/*}}}*/

    public function getConnectionStatus4Write()
    {/*{{{*/
        return $this->getConnectionStatus();
    }/*}}}*/
    private function isConnect() {
        return isset(self::$connections[$this->getConnectionCacheKey()]);
    }
    private function getConnection() {
        return self::$connections[$this->getConnectionCacheKey()];
    }
    private function setConnection($connection) {
        self::$connections[$this->getConnectionCacheKey()] = $connection;
    }
    private function getConnectionCacheKey() {
        return "{$this->dsn}{$this->username};{$this->password};{$this->charset}";
    }
    private function close() {
        $this->connection = NULL;
    }
    public function __sleep() {
        return array('dsn', 'username', 'password', 'charset');
    }
    private static function checkMaxConnection() {
        if (count(self::$connections) >= self::$max_connection_count) {
            array_shift(self::$connections);
        }
    }
}
class RWMysqlDataSource
{
    private $master;
    private $selector;
    private $wc;
    private $rc;
    private $reader;
    private $mustUseMaster = false;
    
    public function __construct($master) {
        $this->master = $master;
        $this->selector = new ObjectRandSelector();
    }
    public function addSlave($slave, $proportion) {
        $this->selector->addSeed($slave, $proportion);
    }
    public function mustUseMaster($must = true) {
        $this->mustUseMaster = $must;
    }
    public function connect4Write() {
        if ($this->wc == null) {
            $this->wc = $this->master->connect4Write();
            $this->reader = $this->master;
        }
        return $this->wc;
    }
    public function connect4Read() {
        if ($this->mustUseMaster) {
            return $this->connect4Write();
        } elseif ($this->rc == null) {
            $this->reader = $this->selector->select();
            $this->rc = $this->reader->connect4Read();
        }
        return $this->rc;
    }

    public function getConnectionStatus4Read()
    {/*{{{*/
        return $this->reader->getConnectionStatus();
    }/*}}}*/

    public function getConnectionStatus4Write()
    {/*{{{*/
        return $this->master->getConnectionStatus();
    }/*}}}*/
}

class ObjectRandSelector
{
    private $seeds = array();
    private $highLimit = 0;
    
    public function addSeed($object, $proportion) {
        if (intval($proportion) <= 1) {
            return;
            //throw new SystemException("Ȩ�ر����Ǵ���1������");
        }
        $this->seeds[] = array(
            'object' => $object,
            'low'    => $this->highLimit,
            'high'   => $this->highLimit + $proportion
        );
        $this->highLimit += $proportion;
    }
    public function select() {
        $rand = mt_rand(1, $this->highLimit);
        foreach ($this->seeds as $seed) {
            if ($seed['low'] <= $rand && $rand <= $seed['high'])
                return $seed['object'];
        }
        throw new SystemException();
    }
}

class OracleDataSource
{
    private $dsn;
    private $username;
    private $password;
    private $connection;

    public function __construct($dbhost, $dbname, $username, $password, $charset='AL32UTF8') {
        $this->dsn = "oci:dbname=//$dbhost:1521/$dbname;charset=$charset";
        $this->username = $username;
        $this->password = $password;
    }
    public function connect4Write() {
        if ($this->isConnect() == false) {
            $this->connection = new PDO($this->dsn, $this->username, $this->password);
            $this->connection->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
            $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->connection->setAttribute(PDO::ATTR_AUTOCOMMIT, true);
        }
        return $this->connection;
    }
    public function connect4Read() {
        return $this->connect4Write();
    }
    public function isConnect() {
        return $this->connection != null;
    }
}

class MSSQLDataSource
{
    private $dsn;
    private $username;
    private $password;
    private $connection;

    public function __construct($dbhost,$dbport, $dbname, $username, $password, $charset='utf8') {
        $this->dsn = "dblib:host=$dbhost:$dbport;dbname=$dbname;charset=$charset";
        $this->username = $username;
        $this->password = $password;
    }
    public function connect4Write() {
        if ($this->isConnect() == false) {
            $this->connection = new PDO($this->dsn, $this->username, $this->password);
            $this->connection->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
            $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            //$this->connection->setAttribute(PDO::ATTR_AUTOCOMMIT, true);
        }
        return $this->connection;
    }
    public function connect4Read() {
        return $this->connect4Write();
    }
    public function isConnect() {
        return $this->connection != null;
    }
    public function mustUseMaster($must = true) {
    }
    public function getConnectionStatus4Read()
    {/*{{{*/
        return null;
    }/*}}}*/

    public function getConnectionStatus4Write()
    {/*{{{*/
        return null;
    }/*}}}*/

}
?>

